package com.wh.wisdomsite.xbox.server.listener;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.wh.wisdomsite.xbox.ba.entity.AppMethod;
import com.wh.wisdomsite.xbox.ba.entity.AppSecret;
import com.wh.wisdomsite.xbox.ba.entity.ServiceMethod;
import com.wh.wisdomsite.xbox.ba.entity.ThreadModel;
import com.wh.wisdomsite.xbox.ba.service.IAppMethodService;
import com.wh.wisdomsite.xbox.ba.service.IAppSecretService;
import com.wh.wisdomsite.xbox.ba.service.IServiceMethodService;
import com.wh.wisdomsite.xbox.ba.service.IThreadModelService;
import com.wh.wisdomsite.xbox.core.ServiceDispatcher;
import com.wh.wisdomsite.xbox.core.event.AfterStartedXboxEvent;
import com.wh.wisdomsite.xbox.core.event.XboxEventListener;
import com.wh.wisdomsite.xbox.common.ServiceMethodHandler;
import com.wh.wisdomsite.xbox.core.threadpool.JobThreadWeightModel;
import com.wh.wisdomsite.xbox.server.manager.SampleAppSecretManager;
import com.wh.wisdomsite.xbox.server.manager.SampleInvokeTimesController;
import com.wh.wisdomsite.xbox.server.manager.SampleServiceAccessController;
import com.wh.wisdomsite.xbox.utils.json.JsonUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.atomic.AtomicInteger;


/***
 * 初始化事件件监听器
 * @Package com.wh.wisdomsite.xbox.entity.client
 * @author 谢泽鹏
 * @date 2016年11月07日 下午15:10
 * @Copyright 个人版权所有
 * @Company 贵州万华科技有限公司Copyright (c) 2016
 * @version V1.0
 */
public class InitConfigDataEventListener implements XboxEventListener<AfterStartedXboxEvent> {

    private static final Log logger = LogFactory.getLog(InitConfigDataEventListener.class);

    private ServiceDispatcher serviceDispatcher;

    private IAppSecretService appSecretService;

    private IServiceMethodService serviceMethodService;

    private IThreadModelService threadModelService;

    private IAppMethodService appMethodService;

    public void setServiceDispatcher(ServiceDispatcher serviceDispatcher) {
        this.serviceDispatcher = serviceDispatcher;
    }

    public void setAppSecretService(IAppSecretService appSecretService) {
        this.appSecretService = appSecretService;
    }

    public void setServiceMethodService(IServiceMethodService serviceMethodService) {
        this.serviceMethodService = serviceMethodService;
    }

    public void setThreadModelService(IThreadModelService threadModelService) {
        this.threadModelService = threadModelService;
    }

    public void setAppMethodService(IAppMethodService appMethodService) {
        this.appMethodService = appMethodService;
    }


    /**
     * 处理事件
     * @param event
     */
    @Override
    public void handleEvent(AfterStartedXboxEvent event) {
        //设置权重模型
        setThreadModel();
        //设置允许服务方法
        setAccessServiceMethod();
        //设置appKey
        setAppKeySecret();
    }

    /**
     * 获取顺序
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }


    /**
     * 设置权重模型
     */
    public void setThreadModel() {
        try {
            //获取权重模型集合
            EntityWrapper<ThreadModel> ewThreadModel = new EntityWrapper<ThreadModel>();
            ewThreadModel.setEntity(new ThreadModel());
            List<ThreadModel> threadModels = threadModelService.selectList(ewThreadModel);
            //构建线程权重模式
            JobThreadWeightModel[] jobThreadWeightModels = new JobThreadWeightModel[threadModels.size()];
            for (int i = 0; i < threadModels.size(); i++) {
                ThreadModel threadModel = threadModels.get(i);
                jobThreadWeightModels[i] = new JobThreadWeightModel(threadModel.getType(), threadModel.getValue(), threadModel.getKey());
            }
            //设置权重模型
            serviceDispatcher.getJobDispathcher().rebuildWeightModel(jobThreadWeightModels);
        } catch (Exception e) {
            e.printStackTrace();
        }
        logger.info("当前线程状态： " + JsonUtil.Json2All(serviceDispatcher.getJobDispathcher().getCurrentThreadStatus()));
        logger.info("设置权重模式成功");
    }


    /**
     * 设置允许服务方法
     */
    public void setAccessServiceMethod() {
        //系统扫描注册的服务方法集合
        Map<String, ServiceMethodHandler> serviceMethodHandlerMap = serviceDispatcher.getXboxContext().getServiceHandlerMap();
        //应用密钥集合
        EntityWrapper<AppSecret> ewAppSecret = new EntityWrapper<AppSecret>();
        ewAppSecret.setEntity(new AppSecret());
        List<AppSecret> appSecretList = appSecretService.selectList(ewAppSecret);

        //数据库提取服务方法集合
        EntityWrapper<ServiceMethod> ewServiceMethod = new EntityWrapper<ServiceMethod>();
        ewServiceMethod.setEntity(new ServiceMethod());
        ewServiceMethod.orderBy("T_METHOD,T_VERSION", true);
        List<ServiceMethod> serviceMethodList = serviceMethodService.selectList(ewServiceMethod);

        //数据库存储的应用－服务方法集合
        EntityWrapper<AppMethod> ewAppMethod = new EntityWrapper<AppMethod>();
        ewAppMethod.setEntity(new AppMethod());
        ewAppMethod.orderBy("T_APP_KEY,T_METHOD", true);
        List<AppMethod> appMethodList = appMethodService.selectList(ewAppMethod);

        //可访问服务方法匹配过程，只取交集
        Map<String, List<String>> serviceAccessMap = new HashMap<String, List<String>>();
        //日志记录  key会method与version的组合
        //Map<String, List<String>> logServiceMap = new HashMap<String, List<String>>();
        //应用请求次数限制
        Map<String, AtomicInteger> appCallLimits = new ConcurrentHashMap<String, AtomicInteger>();
        //app-method请求次数限制
        Map<String, AtomicInteger> appMethodCallLimits = new ConcurrentSkipListMap<String, AtomicInteger>();
        //app-method请求频率
        Map<String, AtomicInteger> appMethodCallRate = new ConcurrentHashMap<String, AtomicInteger>();

        //计算应用的请求次数的限制
        for (AppSecret appSecret : appSecretList) {
            if (appSecret.getStatus() == 1) {
                appCallLimits.put(appSecret.getAppKey(), new AtomicInteger(appSecret.getLimit()));
            }
        }

        //计算应用对应服务方法的访问集合
        for (ServiceMethod sm : serviceMethodList) {
            String methodVersion = sm.getMethod() + "$" + sm.getVersion();
            //查看服务方法是否已注册
            if (serviceMethodHandlerMap.containsKey(methodVersion) && sm.getObsoleted() == 0) {
                //判断应用-服务方法对应关系
                for (AppMethod am : appMethodList) {
                    if (am.getMethod().equals(methodVersion) && am.getStatus() == 1) {
                        // 添加可访问的服务方法
                        if (serviceAccessMap.containsKey(am.getAppKey())) {
                            serviceAccessMap.get(am.getAppKey()).add(methodVersion);
                        } else {
                            List<String> methodVersionList = new ArrayList<String>();
                            methodVersionList.add(methodVersion);
                            serviceAccessMap.put(am.getAppKey(), methodVersionList);
                        }
                    }

                    //判断是否要记录日志  TODO  应该放在for循环外 暂不使用，默认都要写入日志
                    /*if(sm.getLogFlag() == 1){
                        if(logServiceMap.containsKey(am.getAppKey())){
                            logServiceMap.get(am.getAppKey()).add(methodVersion);
                        }else{
                            List<String> methodVersionList = new ArrayList<String>();
                            methodVersionList.add(methodVersion);
                            logServiceMap.put(am.getAppKey(), methodVersionList);
                        }
                    }*/
                }

                //判断是否需要会话记录  TODO 暂进没有使用
                if (sm.getNeedSession() == 1) {
                    serviceMethodHandlerMap.get(methodVersion).getServiceMethodDefinition().setNeedInSession(true);
                } else {
                    serviceMethodHandlerMap.get(methodVersion).getServiceMethodDefinition().setNeedInSession(false);
                }

            }
        }

        //加载应用对服务方法的请求频率和请求限制
        for (AppMethod am : appMethodList) {
            appMethodCallLimits.put(am.getAppKey() + "$" + am.getMethod(), new AtomicInteger(am.getTimes()));
            appMethodCallRate.put(am.getAppKey() + "$" + am.getMethod(), new AtomicInteger(am.getRate()));
        }

        //((DefaultXboxContext)serviceDispatcher.getXboxContext()).setServiceHandlerMap(serviceMethodHandlerMap);
        ((SampleServiceAccessController) serviceDispatcher.getSecurityManager().getServiceAccessController()).setAccessServiceMethod(serviceAccessMap);
        //((SampleServiceAccessController)serviceDispatcher.getSecurityManager().getServiceAccessController()).setLogMap(logServiceMap);
        ((SampleInvokeTimesController) serviceDispatcher.getSecurityManager().getInvokeTimesController()).setAppMethodCallLimit(appMethodCallLimits);
        ((SampleInvokeTimesController) serviceDispatcher.getSecurityManager().getInvokeTimesController()).setAppMethodCallRate(appMethodCallRate);
        ((SampleInvokeTimesController) serviceDispatcher.getSecurityManager().getInvokeTimesController()).setAppCallLimits(appCallLimits);
        logger.info("启动配置数据库成功");
    }


    public void setAppKeySecret() {
        Map<String, String> appAppKeySecretMap = new HashMap<String, String>();
        EntityWrapper<AppSecret> ewAppSecret = new EntityWrapper<AppSecret>();
        ewAppSecret.setEntity(new AppSecret());
        List<AppSecret> appSecretList = appSecretService.selectList(ewAppSecret);
        for (AppSecret as : appSecretList) {
            appAppKeySecretMap.put(as.getAppKey(), as.getSecret());
        }
        ((SampleAppSecretManager) serviceDispatcher.getSecurityManager().getAppSecretManager()).setAppKeySecretMap(appAppKeySecretMap);
    }




}
